package com.wondream.myframework.app.request.gateway.encrypt;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;

/**
 * @author
 */
public class HyTreeDesPKCPaddingUtil {

    /**
     * 算法名称
     */
    private static final String KEY_ALGORITHM = "desede";

    /**
     * 算法名称/加密模式/填充方式
     */
    public static final String CIPHER_ALGORITHM = "DESede/CBC/PKCS5Padding";

    public static final byte[] FIX_KEY = "FC5B8717495251443A9A6D90AF59A3A4FC5B871749525144".getBytes();
    public static final byte[] KEYIV = {8, 7, 6, 5, 4, 3, 2, 1};

    /**
     * CBC加密
     *
     * @param key   密钥
     * @param keyiv IV
     * @param data  明文
     * @return Base64编码的密文
     * @throws Exception
     */
    public static byte[] des3EncodeCBC(byte[] key, byte[] keyiv, byte[] data) throws Exception {
        Security.addProvider(new BouncyCastleProvider());
        Key deskey = keyGenerator(new String(key));
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        IvParameterSpec ips = new IvParameterSpec(keyiv);
        cipher.init(Cipher.ENCRYPT_MODE, deskey, ips);
        return cipher.doFinal(data);
    }

    /**
     * 生成密钥key对象
     *
     * @param keyStr 密钥字符串
     * @return 密钥对象
     * @throws InvalidKeyException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     * @throws Exception
     */
    private static Key keyGenerator(String keyStr) throws Exception {
        byte[] input = hexString2Bytes(keyStr);
        DESedeKeySpec keyspec = new DESedeKeySpec(input);
        SecretKeyFactory keyfactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
        return keyfactory.generateSecret(keyspec);
    }

    private static int parse(char c) {
        if (c >= 'a') {
            return (c - 'a' + 10) & 0x0f;
        }
        if (c >= 'A') {
            return (c - 'A' + 10) & 0x0f;
        }
        return (c - '0') & 0x0f;
    }


    /**
     * 从十六进制字符串到字节数组转换
     *
     * @param hexstr
     * @return
     */
    private static byte[] hexString2Bytes(String hexstr) {
        byte[] b = new byte[hexstr.length() / 2];
        int j = 0;
        for (int i = 0; i < b.length; i++) {
            char c0 = hexstr.charAt(j++);
            char c1 = hexstr.charAt(j++);
            b[i] = (byte) ((parse(c0) << 4) | parse(c1));
        }
        return b;
    }

    /**
     * CBC解密
     *
     * @param key   密钥
     * @param keyiv IV
     * @param data  Base64编码的密文
     * @return 明文
     * @throws Exception
     */
    public static byte[] des3DecodeCBC(byte[] key, byte[] keyiv, byte[] data) throws Exception {
        Key deskey = keyGenerator(new String(key));
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        IvParameterSpec ips = new IvParameterSpec(keyiv);
        cipher.init(Cipher.DECRYPT_MODE, deskey, ips);
        return cipher.doFinal(data);
    }

    public static byte[] getKeyBytes(String keyStr) throws Exception {
        if (null == keyStr || keyStr.length() < 1) {
            System.out.println("key为空");
            return null;
        }
        MessageDigest alg = MessageDigest.getInstance("MD5");
        alg.update(keyStr.getBytes(StandardCharsets.UTF_8));
        byte[] sourceBytes = alg.digest();
        byte[] result = new byte[24];
        for (int i = 0; i < 24; i++) {
            result[i] = sourceBytes[i % 16];
        }

        return result;
    }

    public static String getDes3Encode(String decodeStr) {
        try {
            return HyTreeDesECBUtils.byte2HexStr(HyTreeDesPKCPaddingUtil.des3EncodeCBC(HyTreeDesPKCPaddingUtil.FIX_KEY, HyTreeDesPKCPaddingUtil.KEYIV, (decodeStr).getBytes(StandardCharsets.UTF_8)));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String getDes3Decode(String encodeStr) {
        try {
            return new String(HyTreeDesPKCPaddingUtil.des3DecodeCBC(FIX_KEY, KEYIV, HyTreeDesECBUtils.hexStringToBytes(encodeStr)), StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static void main(String[] args) {
        System.out.println(getDes3Decode("F2849D65BE34BF91"));
        System.out.println(getDes3Encode("52110000024185"));
    }
}